/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
 */

import { expect, test } from '@jest/globals';
import * as fse from 'fs-extra';
import * as path from 'path';
import { resolve } from 'path';

import { ModuleBuildProfile } from '../../src/options/build/module-build-profile';

import {
  initByStageEmptyApp,
  initByStageEmptyService,
  initExecuteCommand,
  runHvigor,
  runShouldFail
} from './common/common';
import { ModuleBuildProfileModifier } from './common/modifier/module-build-profile-modifier';
import { PackageJsonModifier } from './common/modifier/package-json-modifier';
import { ProjectBuildProfileModifier } from './common/modifier/project-build-profile-modifier';
import { Probes } from './common/probes';
import ModuleTargetBuildOpt = ModuleBuildProfile.ModuleTargetBuildOpt;

describe('build hsp signing test', () => {
  test.concurrent('test hsp not signing', async () => {
    await initByStageEmptyApp(async (projectRoot) => {
      const commands = initExecuteCommand({
        mode: 'module',
        module: 'slibrary',
        product: 'default',
        tasks: 'assembleHsp'
      });
      await testHapSignFalse(projectRoot, commands);
    }, { sign: false });
  });

  test.concurrent('test hsp signing', async () => {
    await initByStageEmptyApp(async (projectRoot) => {
      const commands = initExecuteCommand({
        mode: 'module',
        module: 'slibrary',
        product: 'default',
        tasks: 'assembleHsp'
      });
      await testHapSignTrue(projectRoot, commands);
    }, { sign: true });
  });

  test.concurrent('test stage service package hsp not signing', async () => {
    await initByStageEmptyService(async (projectRoot) => {
      const commands = initExecuteCommand({
        mode: 'module',
        module: 'slibrary',
        product: 'default',
        tasks: 'assembleHsp'
      });
      await testHapServiceSignFlase(projectRoot, commands, 'slibrary');
    }, { sign: false });
  });
});

describe('build hsp else tests', function () {
  test.concurrent('test with nested module path', async () => {
    await initByStageEmptyApp(async (projectRoot) => {
      fse.moveSync(path.resolve(projectRoot, 'slibrary'), path.resolve(projectRoot, 'hsp/slibrary'));
      const projectBuildProfileModifier = new ProjectBuildProfileModifier(projectRoot);
      projectBuildProfileModifier.updateModule({
        'name': 'slibrary',
        'srcPath': './hsp/slibrary',
        'targets': [
          {
            'name': 'default',
            'applyToProducts': [
              'default'
            ]
          }
        ]
      }).outputSync();

      const commands = initExecuteCommand({
        mode: 'module',
        module: 'slibrary',
        product: 'default',
        tasks: 'assembleHsp'
      });
      await testHapSignFalse(projectRoot, commands);
    }, { sign: false });
  });

  test.concurrent('test with local depends', async () => {
    await initByStageEmptyApp(async (projectRoot) => {
      const commands = initExecuteCommand({
        mode: 'module',
        module: 'slibrary',
        product: 'default',
        tasks: 'assembleHsp'
      });
      await testHapSignFalse(projectRoot, commands);
      const probe = new Probes(projectRoot, resolve(projectRoot, 'slibrary'));
      expect(fse.readdirSync(probe.getModuleBuildOutputPath())).toContain('slibrary.har');
      expect(fse.readdirSync(probe.getModuleBuildOutputPath())).toContain('slibrary-default-unsigned.hsp');
    }, {
      sign: false,
      runNpmInstall: true,
      prepare: async (projectRoot) => {
        const packageJsonModifier = new PackageJsonModifier(projectRoot, 'slibrary');
        packageJsonModifier.setDependencies({
          'library': '../library'
        }).outputSync();
      }
    });
  });

  test.concurrent('test change diff target with entry', async () => {
    await initByStageEmptyApp({
      prepare: async (projectRoot) => {
        const packageJsonModifier = new PackageJsonModifier(projectRoot, 'entry');
        packageJsonModifier.setDependencies({
          'slibrary': '../slibrary'
        }).outputSync();
      },
      runNpmInstall: true,
      cb: async (projectRoot) => {
        const entryBuildProfile = new ModuleBuildProfileModifier(projectRoot, 'entry');
        const entryTarget: ModuleTargetBuildOpt = {
          name: 'mini'
        };
        entryBuildProfile.updateTarget(entryTarget).outputSync();
        const slibraryBuildProfile = new ModuleBuildProfileModifier(projectRoot, 'slibrary');
        const slibraryTarget: ModuleTargetBuildOpt = {
          name: 'mini'
        };
        slibraryBuildProfile.updateTarget(slibraryTarget).outputSync();
        const commands = initExecuteCommand({
          mode: 'module',
          module: 'entry@mini',
          product: 'default',
          tasks: 'assembleHap'
        });
        const result = runHvigor(projectRoot, commands);

        expect(result.stdout.includes('BUILD SUCCESSFUL')).toBeTruthy();

        slibraryBuildProfile.removeLastTarget().outputSync();
        runShouldFail(projectRoot, commands, 'Make sure module \'slibrary\' has the same target as module \'entry\'.');
      }
    }
    );
  });
});

export async function testHapServiceSignFlase(projectRoot: string, commands: string[], moduleName: string) {
  const result = runHvigor(projectRoot, commands);
  const moduleStr = `${moduleName}:default`;
  expect(result.stderr)
    .toContain('Will skip sign \'hos_hap\'. No signingConfigs profile is configured in current project');
  expect(result.stdout).toContain(`Finished :${moduleStr}@SignHsp`);
  expect(result.stdout).toContain('BUILD SUCCESSFUL');
}

export async function testHapSignFalse(projectRoot: string, commands: string[]) {
  const result = runHvigor(projectRoot, commands);
  const moduleStr = 'slibrary:default';

  expect(result.stderr)
    .toContain('Will skip sign \'hos_hap\'. No signingConfigs profile is configured in current project');

  expect(result.stdout).toContain(`Finished :${moduleStr}@SignHsp`);
  expect(result.stdout).toContain('BUILD SUCCESSFUL');
}

export async function testHapSignTrue(projectRoot: string, commands: string[]) {
  const result = runHvigor(projectRoot, commands);
  const moduleStr = 'slibrary:default';

  expect(result.stdout).toContain(`Finished :${moduleStr}@SignHsp`);
  expect(result.stdout).toContain('BUILD SUCCESSFUL');
  const result2 = runHvigor(projectRoot, commands);
  expect(result2.stdout).toContain(`UP-TO-DATE :${moduleStr}@SignHsp`);
  expect(result2.stdout).toContain('BUILD SUCCESSFUL');
  const output = path.resolve(projectRoot, 'slibrary/build/default/outputs');
  await fse.removeSync(output);
  const result3 = runHvigor(projectRoot, commands);
  expect(result3.stdout).toContain(`Finished :${moduleStr}@SignHsp`);
  expect(result3.stdout).toContain('BUILD SUCCESSFUL');
}
